#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <queue>
#include <functional>

#include "Thread.hpp"
#include "Log.hpp"
#include "Lockguard.hpp"

using namespace threadmoudle;
using namespace log_ns;

static const int gdefaultnum = 5;

void test()
{
    while (true)
    {
        std::cout << "hello,world";
        sleep(1);
    }
}
template <typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void Wakeup() //唤醒单个
    {
        pthread_cond_signal(&_cond);
    }
    void WakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond,&_mutex);
    }
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    void HandlerTask(const std::string &name)
    {
        while (true)
        {
            //1.取任务
            LockQueue();
            while (IsEmpty() && _isrunning)
            {
                _sleep_thread_num++;
                LOG(INFO,"%s thread sleep begin!\n",name.c_str());
                Sleep();
                LOG(INFO,"%s thread wakeup!\n",name.c_str());
                _sleep_thread_num--;
            }
            // 判定一种情况
            if(IsEmpty() && !_isrunning)
            {
                UnLockQueue();
                LOG(INFO,"%s thread quit\n",name.c_str());
            }
            // 有任务
            T t=_task_queue.front();
            _task_queue.pop();
            UnLockQueue();
            // 处理任务
            t();// 处理任务，此处不用/不能在临界区中处理
            // std::cout << name << ": " << t.result() << std::endl;
            LOG(DEBUG,"hander task done,task is:%s\n",t.result().c_str());
        }
        
    }

    void Init()
    {
        func_t func=std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1);
        for(int i=0;i<_thread_num;i++)
        {
            std::string threadname="thread-"+std::to_string(i+1);
            _threads.emplace_back(threadname,func);
            LOG(DEBUG, "construct thread %s done, init success\n", threadname.c_str());
        }
    }

    void Srart()
    {
        _isrunning=true;
        for(auto & thread:_threads)
        {
            LOG(DEBUG,"start thread %s done.\n",thread.Name().c_str());
            thread.Start();
        }
    }

    ThreadPool(int thread_num=gdefaultnum):_thread_num(thread_num),_isrunning(false),_sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }
    ThreadPool(const ThreadPool<T> &)=delete;
    void operator=(const ThreadPool<T> &)=delete;
public:
    void Stop()
    {
        LockQueue();
        _isrunning=true;
        WakeupAll();
        UnLockQueue();
        LOG(INFO, "Thread Pool Stop Success!\n");
    }
    //单例
    static ThreadPool<T> *GetInstance()
    {
        if(_tp==nullptr) //此时类中没有对象，那么多个线程就会来到锁的位置，竞争锁。必然只能有一个线程竞争锁成功
        {                   //双判定，减少锁的征用，提高获取单例的效率
            Lockguard lockguard(&_sig_mutex);
            if(_tp==nullptr) //再次判断有没有对象被创建
            {
                LOG(INFO, "create threadpool\n");
                _tp=new ThreadPool();
                _tp->Init();
                _tp->Srart();

            }
            else{
                LOG(INFO, "get threadpool\n");
            }
        }
        return _tp;
    } 

    void Equeue(const T &in)
    {
        LockQueue();
        if(_isrunning)
        {
            _task_queue.push(in);
            if(_sleep_thread_num>0)
            {
               Wakeup();
            }
        }
        UnLockQueue();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }
private:
    int _thread_num;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    bool _isrunning;
    int _sleep_thread_num;  //当前处于休眠的线程数目
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    //单例
    // volatile static ThreadPool<T> *_tp;

    static ThreadPool<T> *_tp;  
    static pthread_mutex_t _sig_mutex;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <typename T>
pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;
